package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Service
public class TestServiceImpl implements TestService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedissonClient redissonClient;
    public  void testLock1() {

//    String value= (String) stringRedisTemplate.opsForValue().get("Lock");
//    if (StringUtils.isBlank(value)){
//        return;
//    }
//
//    int num = Integer.parseInt(value);
//    stringRedisTemplate.opsForValue().set("Lock",String.valueOf(++num));
//    }
        String uuid = UUID.randomUUID().toString();
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid, 10, TimeUnit.SECONDS);
//        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent("Lock", "Lock");
         if (flag){
             //获取锁,
             String value = stringRedisTemplate.opsForValue().get("num");
             if (StringUtils.isBlank(value)){
                 return;
             }
             int num = Integer.parseInt(value);
             stringRedisTemplate.opsForValue().set("num",String.valueOf(++num));
//             stringRedisTemplate.delete("Lock");
             //4.1 先创建脚本对象 DefaultRedisScript泛型脚本语言返回值类型 Long 0：失败 1：成功
             DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
             //4.2设置脚本文本
             String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                     "then\n" +
                     "    return redis.call(\"del\",KEYS[1])\n" +
                     "else\n" +
                     "    return 0\n" +
                     "end";
             redisScript.setScriptText(script);
             //4.3 设置响应类型
             redisScript.setResultType(Long.class);
             stringRedisTemplate.execute(redisScript, Arrays.asList("lock"), uuid);
         }else {
             try {
                 Thread.sleep(100);
                 this.testLock();
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
         }

    }

    @Override
    public void testLock() {
        RLock lock = redissonClient.getLock("lock");
        lock.lock();

        try {
            String value = stringRedisTemplate.opsForValue().get("num");
            if (StringUtils.isBlank(value)){
                return;
            }
            int num = Integer.parseInt(value);
            stringRedisTemplate.opsForValue().set("num",String.valueOf(++num));
            this.check();
        } catch (NumberFormatException e) {
            throw new RuntimeException(e);
        }finally {
            lock.unlock();
        }


    }

    @Override
    public String read() {

        //1.创建读写锁对象
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readWriteLock");
        //2.获取读锁
        RLock lock = readWriteLock.readLock();
        //加锁 给锁的有效期设置为10s
        lock.lock(10, TimeUnit.SECONDS);
        //3.执行从redis获取数据业务
        String msg = stringRedisTemplate.opsForValue().get("msg");
        //4.释放读锁
        //lock.unlock();
        return msg;

    }

    @Override
    public void write() {
         //1.创建读写锁对象
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readWriteLock");
        //2.获取写锁
        RLock lock = readWriteLock.writeLock();
        //加锁 给锁的有效期设置为10s
        lock.lock(10, TimeUnit.SECONDS);

        //3.业务将数据写入redis
        stringRedisTemplate.opsForValue().set("msg", "msgData");

        //4.释放写锁
        //lock.unlock();
    }

    private void check() {
        RLock lock = redissonClient.getLock("lock1");
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"执行了");
        lock.unlock();
    }

}
